#include <QApplication>
#include <cmath>
#include "Basic.h"
#include "XWav.h"
#include <cassert>


const int MAX_HEADER_LEN = 1000;


XWav::XWav(QWidget *parent) : QWidget(parent) {
	srateEdit = new QLabel();
	frameEdit = new QLabel();
	//srateEdit->setReadOnly(true);
	//frameEdit->setReadOnly(true);
	windowEdit = new QSpinBox();
	windowLabel = new QLabel();
	headerEdit = new QSpinBox();
	progressBar = new QProgressBar();

	connect(windowEdit, SIGNAL(valueChanged(int)), this, SLOT(windowEditChanged(int)));

	QGridLayout *layout = new QGridLayout();
	layout->addWidget(new QLabel("Sample Rate:"), 0, 0, 1, 1);
	layout->addWidget(srateEdit, 0, 1, 1, 1);
	layout->addWidget(new QLabel("Frames:"), 1, 0, 1, 1);
	layout->addWidget(frameEdit, 1, 1, 1, 1);
	layout->addWidget(new QLabel("Window Width:"), 0, 3, 1, 1);
	layout->addWidget(windowEdit, 0, 4, 1, 1);
	layout->addWidget(new QLabel("Window Time:"), 1, 3, 1, 1);
	layout->addWidget(windowLabel, 1, 4, 1, 1);
	layout->addWidget(new QLabel("Window Head:"), 2, 3, 1, 1);
	layout->addWidget(headerEdit, 2, 4, 1, 1);

	layout->addWidget(new QLabel("Progress:"), 3, 0, 1, 1);
	layout->addWidget(progressBar, 3, 1, 1, 4);
	setLayout(layout);

	//progressBar->setVisible(false);
}


void XWav::windowEditChanged(int value) {
	/* disable warning */ if (value == 1) value = 0;
	headerEdit->setMaximum(windowEdit->value());
	double w = (double)windowEdit->value() / (double)samplerate * 1000.;
	windowLabel->setText(QString("(T: %1ms)").arg(w, 0, 'f', 2));
	headerEdit->setMinimum(1);
	headerEdit->setMaximum(std::min(windowEdit->value(), MAX_HEADER_LEN));
}


void XWav::update(QString inputFile) {
	this->inputFile = inputFile;
	SndfileHandle wav(inputFile.toStdString());
	srateEdit->setText(QString::number(wav.samplerate()));
	frameEdit->setText(QString::number(wav.frames()));

	windowEdit->setMinimum(1);
	windowEdit->setMaximum((int)wav.frames());
	samplerate = wav.samplerate();
	windowEditChanged(windowEdit->value());
}


void XWav::setParameters(int w, int h) {
	windowEdit->setValue(w);
	headerEdit->setValue(h);
}


void XWav::convert(QString outputFile) {
/*
out << "NOW DEBUGGING convert..." << endl;
const int N = 9;
const int M = 4;
XSegment *seg= new XSegment(1, N, M);
int *p = new int[N];
for (int i = 0; i < N; ++i) p[i] = i * i;
for (int i = 0; i < N; ++i) out << "  p[" << i << "] = " << p[i] << endl;
seg->make(p);
seg->get(p);
for (int i = 0; i < N; ++i) out << "  z[" << i << "] = " << p[i] << endl;
return;
*/

	SndfileHandle wav(inputFile.toStdString());
	//SndfileHandle wav("/home/chris/programming/lpa-codec/data/1874.wav");

	out << "[XWav::convert]" << endl;
	out << "Input  : " << inputFile << endl;
	out << "Output : " << outputFile << endl;
	out << "Opened " << inputFile << "." << endl;
	out << "    Sample rate : " << wav.samplerate() << endl;
	out << "    Channels    : " << wav.channels() << endl;
	out << "    Frames      : " << wav.frames() << endl;
	out << "    Error       : " << wav.strError() << endl;

	progressBar->setRange(0, 100);

	XPara para;
	para.channels = wav.channels();
	para.samplerate = wav.samplerate();
	para.frames = wav.frames();
	para.window = windowEdit->value();
	para.hlen = headerEdit->value();

	std::ofstream file(outputFile.toStdString().c_str(), std::ios::binary);
	file.write((char*)(&para), sizeof(para));

	//SNR snr;
	double *buf = new double[para.window * para.channels];
	short *buf2 = new short[para.window * para.channels];
	XSegment *segment = new XSegment(para.channels, para.window, para.hlen);

	for (sf_count_t cur = 0; cur < wav.frames(); cur += para.window) {
		progressBar->setValue(progressBar->maximum() * cur / wav.frames());

		int n = para.window;
		int hlen = para.hlen;
		if (cur + n > wav.frames()) {
			n = (int)(wav.frames() - cur);
			hlen = std::min(n, para.hlen);
			delete segment;
			segment = new XSegment(para.channels, n, hlen);
		}

		sf_count_t readCnt = wav.read(buf2, n * para.channels);
		for (int i = 0; i < para.window * para.channels; ++i)
			buf[i] = buf2[i];
		if (readCnt < (sf_count_t)n * para.channels) {
			out << "ERROR [XWav::convert]: readCnt != n * para.channels" << endl;
			out << "   readCnt  = " << readCnt << endl;
			out << "   n        = " << n << endl;
			out << "   channels = " << para.channels << endl;
			out << "   cur      = " << cur << endl;
			exit(-1);
			for (int i = (int)readCnt; i < n * para.channels; ++i)
				buf[i] = 0;
		}
__c1=0;
		segment->make(buf);
		segment->save(file);
//printf("DDDDDDDDDDDDDDDDEBUG!!!\n");
//printf("win=%d\n", para.window);
//printf("len=%d\n", para.hlen);
	//segment->make(buf);
//for(int i=0; i<n; ++i) buf[i]=0.;
/*
static int _=0; if(_++==2 || false) {
	segment->make(buf);
	segment->print();
	segment->get(buf);
	double err=0;
FILE *fr = fopen("../visual/red.tex", "w");
FILE *fg = fopen("../visual/green.tex", "w");
FILE *fb = fopen("../visual/blue.tex", "w");
FILE *fe = fopen("../visual/err.tex", "w");
//FILE *fe2 = fopen("../visual/err2.tex", "w");
//FILE *fez = fopen("../visual/errz.tex", "w");
	for(int i=0; i<n; ++i){
		//printf("buf[%d]= %7hd %.4lf\n",i,buf2[i],buf[i]);
		fprintf(fr, "%.5lf %.5lf\n", (double)(i+1), double(buf2[i])/32767.);
		fprintf(fg, "%.5lf %.5lf\n", (double)(i+1), buf[i]/32767.);
		fprintf(fe, "%.5lf %.5lf\n", (double)(i+1), double(buf2[i]-buf[i])/32767.);
		#define sqr(x) ((x)*(x))
		err+=sqr((double)buf2[i]-buf[i]);
		#undef sqr
	}
	__c1=1; segment->get(buf);
	for(int i=0; i<n; ++i){
		fprintf(fb, "%.5lf %.5lf\n", (double)(i+1), buf[i]/32767.);
	}
fclose(fr);
fclose(fg);
fclose(fb);
fclose(fe);
	err=sqrt(err/n);
	printf("err=%.6lf\n", err);
	__c1=0;
}
*/
	}
	delete segment;
	delete buf;
	file.close();

	//out << "Signal to Noise Ratio: " << snr.value() << endl;

	/*

	outputFile += ".wav";
	SndfileHandle lpa(outputFile.toStdString(),
		SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_PCM_16,
		wav.channels(), wav.samplerate());

	int *buf = new int[wav.channels() * 1024 * 1024];
	size_t finished = 0;
	progressBar->setRange(0, 100);
	while (1) {
		size_t cnt = wav.read(buf, 1024 * 1024);
		if (cnt == 0)
			break;
	out << "cnt = " << cnt << endl;
		for (size_t i = 0; i < cnt / 2; ++i)
			for (int j = 0; j < wav.channels(); ++j)
				buf[i*wav.channels() + j] = buf[(i/1000*1000*2+i%1000)*wav.channels() + j];
		lpa.write(buf, cnt / 2);
		finished += cnt;
		progressBar->setValue(100 * finished / wav.frames());
	}
	*/
	progressBar->setValue(100);
	sleep(100);
	progressBar->reset();

	out << "[XWav::convert] Finished." << endl;
}
